home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / uudecode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  13.4 KB  |  513 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 46
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. /* Major modifications Copyright (c)1991-1992, Apple Computer Inc. */
  4. /************************************************************************
  5.  * functions to convert files from uuencoded applesingle (yuck!)
  6.  * Major modifications (c)1991-1992, Apple Computer Inc.
  7.  * released to public domain.
  8.  ************************************************************************/
  9. #pragma load EUDORA_LOAD
  10. #pragma segment Abomination
  11.  
  12. typedef struct
  13. {
  14.     uLong type;
  15.     uLong offset;
  16.     uLong length;
  17. } Map, *MapPtr;
  18.  
  19. typedef struct
  20. {
  21.     uLong magic;
  22.     uLong version;
  23.     char homefs[16];
  24.     uShort mapCount;
  25.     Map maps[9];
  26. } UUHeader;
  27.  
  28. typedef struct
  29. {
  30.     UUHeader header; /* AppleSingle header */
  31.     AbStates state; /* Current decoder state */
  32.     UHandle buffer; /* receive map buffer */
  33.     short bSpot; /* current point in receive map buffer */
  34.     short bSize; /* Size of receive map buffer */
  35.     short vRef; /* volref num for file */
  36.     short refN; /* current file refnum */
  37.     Str63 name; /* real file name */
  38.     Str63 tmpName; /* temporary file name */
  39.     long offset; /* Offset into the stream */
  40.     long currmap; /* Current map that we are working on, set in AbNextState */
  41.     Boolean seenFinfo; /* Have we found the Finfo in the stream yet? */
  42.     Boolean seenName; /* Have we found the real file name in the stream yet? */
  43.     Boolean hasName; /* Are we going to find the real file name in the stream ? */
  44.     Boolean usedTemp; /* Did we use a temporary name? */
  45.     Boolean noteAttached; /* Did we attache the enclosure note yet? */
  46.     FInfo info; /* Macintosh file information */
  47. } UUGlobals, **UUGlobalsHandle;
  48.  
  49. UUGlobalsHandle UUG;
  50. #define Header (*UUG)->header
  51. #define HeaderData ((UPtr)&Header)
  52. #define State (*UUG)->state
  53. #define Buffer (*UUG)->buffer
  54. #define BSpot (*UUG)->bSpot
  55. #define BSize (*UUG)->bSize
  56. #define VRef (*UUG)->vRef
  57. #define Name (*UUG)->name
  58. #define TmpName (*UUG)->tmpName
  59. #define Maps Header.maps
  60. #define Info (*UUG)->info
  61. #define InfoData ((UPtr)&Info)
  62. #define RefN (*UUG)->refN
  63. #define Offset (*UUG)->offset
  64. #define CurrMapNum (*UUG)->currmap
  65. #define CurrMap Header.maps[(*UUG)->currmap]
  66. #define SeenFinfo (*UUG)->seenFinfo
  67. #define SeenName (*UUG)->seenName
  68. #define HasName (*UUG)->hasName
  69. #define UsedTemp (*UUG)->usedTemp
  70. #define NoteAttached (*UUG)->noteAttached
  71.  
  72. short UULine(UPtr text, long size);
  73. Boolean UUData(uShort byte);
  74. short AbOpen(void);
  75. short AbClose(void);
  76. short AbWriteBuffer(void);
  77. Boolean AbNameStuff(uShort byte);
  78. Boolean AbNextState( void );
  79. Boolean AbTempName( void );
  80. Boolean AbSetFinfo(uShort byte);
  81. Boolean BeginAbomination( void );
  82.  
  83. /************************************************************************
  84.  * IsAbLine - does the UUencoded applesingle file begin?
  85.  ************************************************************************/
  86. #pragma segment POP
  87. Boolean IsAbLine(UPtr text, long size)
  88. {
  89.     UPtr spot;
  90.     Str63 name;
  91.     char *namePtr;
  92.     short i = 0;
  93.     
  94.     namePtr = name;
  95.     if (size<11) return(False);
  96.     if (strncmp(text,"begin ",6)) return(False);
  97.     spot = text + 7;
  98.     while (*spot>='0' && *spot<='7') spot++;
  99.     if (*spot!=' ' || spot-text > 10) return(False);
  100.     if (spot[1]=='\n') return(False);
  101.     if( !BeginAbomination() ) return(False);
  102.     namePtr++; /* Skip the size */
  103.     while( (*spot++ != '\n') && (i < 63) ){
  104.                 *namePtr++ = *spot;
  105.                 i++;
  106.     }
  107.                 if( i>27 ) i = 27; /* Trim filname so number can fit on end */
  108.     name[0] = i;
  109.     PCopy(Name,name);
  110.     return(True);
  111. }
  112.  
  113. Boolean BeginAbomination( void )
  114. {
  115.     if (UUG==nil)
  116.     {
  117.         if ((UUG=NewZH(UUGlobals))==nil) return( false );
  118.         State = AbDone;
  119.         Offset = -1;
  120.                                 SeenFinfo = false;
  121.                                 NoteAttached = false;
  122.                                 SeenName = false;
  123.                                 HasName = false;
  124.                                 UsedTemp = false;
  125.     }
  126.     return( true );
  127. }
  128.  
  129. /************************************************************************
  130.  * SaveAbomination - returns the state of the converter
  131.  ************************************************************************/
  132. short SaveAbomination(UPtr text, long size)
  133. {
  134.     if (!text)
  135.     {
  136.         if (UUG)
  137.         {
  138.             if (AbClose()) BadBinHex = True;
  139.             if (Buffer) DisposHandle(Buffer);
  140.             ZapHandle(UUG);
  141.         }
  142.         return(AbDone);
  143.     }
  144.     if (!BeginAbomination()) return(AbDone);
  145.     return(UULine(text,size));
  146. }
  147.  
  148. #pragma segment Abomination
  149. #define UU(c) (((c)-' ')&077)
  150. /************************************************************************
  151.  * UULine - handle a line of uuencoded stuff
  152.  ************************************************************************/
  153. short UULine(UPtr text, long size)
  154. {
  155.     short length = UU(*text);
  156.     Boolean result=True;
  157.     
  158.     if ((size==3 || size==4) && !striscmp("end\n",text))
  159.         return(SaveAbomination(nil,0));
  160.         
  161.     if (*text<' ' || *text>'`')
  162.     {
  163.         WarnUser(BINHEX_BADCHAR,*text);
  164.         SaveAbomination(nil,0);
  165.         BadBinHex = True;
  166.         return(AbDone);
  167.     }
  168.     text++; size--;
  169.     if (State==AbDone) State=NotAb;
  170.     if (length<=0) return(State);
  171.     if (text[size-1]=='\n') size--;
  172.     if ((length+2)/3 != ((size*3)/4)/3)
  173.     {
  174.         WarnUser(UU_BAD_LENGTH,(length+2)/3-((size*3)/4)/3);
  175.         SaveAbomination(nil,0);
  176.         return(AbDone);
  177.     }
  178.             
  179.     for (;length>0;text+=4,length-=3)
  180.     {
  181.         if (text[0]<' ' || text[0]>'`' || text[1]<' ' || text[1]>'`' ||
  182.                 length>1 && (text[2]<' ' || text[2]>'`') ||
  183.                 length>2 && (text[3]<' ' || text[3]>'`'))
  184.         {
  185.             WarnUser(BINHEX_BADCHAR,0);
  186.             SaveAbomination(nil,0);
  187.             BadBinHex = True;
  188.             return(AbDone);
  189.         }
  190.         if (!(result=UUData(0xff & (UU(text[0])<<2 | UU(text[1])>>4)))) break;
  191.         if (length>1 && !(result=UUData(0xff & (UU(text[1])<<4 | UU(text[2])>>2))))
  192.             break;
  193.         if (length>2 && !(result=UUData(0xff & (UU(text[2])<<6 | UU(text[3])))))
  194.             break;
  195.     }
  196.     if (!result) return(SaveAbomination(nil,0));
  197.     return(State);
  198. }
  199.  
  200. /************************************************************************
  201.  * UUData - handle a data character
  202.  ************************************************************************/
  203. Boolean UUData(uShort byte)
  204. {
  205.     Boolean result=True;
  206.     
  207.     Offset++;
  208.     switch (State)
  209.     {
  210.         case NotAb:
  211.                                 State = AbHeader;
  212.         case AbHeader:
  213.                                 HeaderData[BSpot++] = byte;
  214.                                 if (BSpot>=(sizeof(UUHeader)-(sizeof(Map)*9))) {
  215.                                                 if( Header.magic != 0x00051600 ) {
  216.                                                                 WarnUser(UU_BAD_ENCLOSURE,Header.magic);
  217.                                                                 SaveAbomination(nil,0);
  218.                                                                 BadBinHex = True;
  219.                                                                 return(false);
  220.                                                 }
  221.                                                 if( (Header.version != 0x00010000) && (Header.version != 0x00020000) ) {
  222.                                                                 WarnUser(UU_BAD_VERSION,Header.version);
  223.                                                                 SaveAbomination(nil,0);
  224.                                                                 BadBinHex = True;
  225.                                                                 return(false);
  226.                                                 }
  227.                                                 if( (Header.mapCount<1) || (Header.mapCount>9) ) {
  228.                                                                 WarnUser(UU_INVALID_MAP,Header.mapCount);
  229.                                                                 SaveAbomination(nil,0);
  230.                                                                 BadBinHex = True;
  231.                                                                 return(false);
  232.                                                 }
  233.                                 }
  234.                                 if( BSpot>=(sizeof(UUHeader) - (sizeof(Map) * (9 - Header.mapCount))) ) {
  235.                                                 AbNextState();
  236.                                                 if(State != AbName){
  237.                                                                 result = AbTempName();
  238.                                                 }
  239.                                                 BSpot = 0;
  240.                                 }
  241.                                 break;
  242.                                 
  243.     case AbName:
  244.         if (Offset<CurrMap.offset) break;
  245.         result = AbNameStuff(byte);
  246.         break;
  247.                 
  248.                 case AbFinfo:
  249.         if (Offset<CurrMap.offset) break;
  250.         result = AbSetFinfo(byte);
  251.         break;
  252.  
  253.     case AbResFork:
  254.                 case AbDataFork:
  255.                                 if (Offset<CurrMap.offset) break;
  256.                                 if (!CurrMap.length) {
  257.                                                 result = !AbClose();
  258.                                                 Offset--;AbNextState();
  259.                                                 if (result) {result=UUData(byte);}
  260.                                 }
  261.                                 else if (!RefN && AbOpen())
  262.                                                 result = False;
  263.                                 else {
  264.                                                 (*Buffer)[BSpot++] = byte;
  265.                                                 CurrMap.length--;
  266.                                                 if (BSpot>=BSize && AbWriteBuffer()) result=False;
  267.                                 }
  268.                                 break;
  269.                                 
  270.                 case AbSkip:
  271.                                 if( Offset < CurrMap.offset ) break;
  272.                                 if( !CurrMap.length ) {
  273.                                                 Offset--;
  274.                                                 AbNextState();
  275.                                                 BSpot = 0;
  276.                                                 result = UUData( byte );
  277.                                 } else {
  278.                                                 CurrMap.length--;
  279.                                 }
  280.                                 break;
  281.                                 
  282.                 default:
  283.                                 /* invalid state! */
  284.                                 WarnUser(UU_INVALID_STATE,0);
  285.                                 result = False;
  286.     }
  287.     return(result);         
  288. }
  289.  
  290. Boolean AbTempName( void )
  291. {
  292.     Str63 name;
  293.     short vRef;
  294.     short err;
  295.  
  296.     UsedTemp = true;
  297.     PCopy(name, Name);
  298.     if (AutoWantTheFile(name,&vRef,False) || WantTheFile(name,&vRef))
  299.     {
  300.         VRef = vRef;
  301.         PCopy(TmpName,name);
  302.                                 PCopy(Name,name);
  303.         if (err=MakeResFile(name,VRef,0,'CSOm','TEMP'))
  304.         {
  305.             FileSystemError(BINHEX_CREATE,name,err);
  306.             (void) SaveAbomination(nil,0);
  307.             return(False);
  308.         }
  309.                 AbNextState();
  310.         BSpot = 0;
  311.     }
  312.     else
  313.     {
  314.         State = AbDone;
  315.         return(False);
  316.     }
  317.     
  318.     return(True);
  319. }
  320.  
  321.  
  322. Boolean AbNameStuff(uShort byte)
  323. {
  324.     Str63 name;
  325.     short vRef;
  326.     short err;
  327.  
  328.     Name[++BSpot] = byte;
  329.     if (BSpot<CurrMap.length) return(True);
  330.                 if (CurrMap.length > 27){ /* Trim name so number fits! */
  331.                                 *Name = 27;
  332.                 } else {
  333.                 *Name = CurrMap.length;
  334.                 }
  335.     PCopy( name, Name );
  336.     SeenName = true;
  337.     if( !UsedTemp ){
  338.                     if (AutoWantTheFile(name,&vRef,False) || WantTheFile(name,&vRef))
  339.                     {
  340.                                 VRef = vRef;
  341.                                 PCopy( Name, name );
  342.                                 PCopy( TmpName, name );
  343.                                 if (err=MakeResFile(name,VRef,0,'CSOm','TEMP'))
  344.                                 {
  345.                                     FileSystemError(BINHEX_CREATE,name,err);
  346.                                     (void) SaveAbomination(nil,0);
  347.                                     return(False);
  348.                                 }
  349.                                 AbNextState();
  350.                                 BSpot = 0;
  351.                                 if( SeenFinfo ){
  352.                                                 AddAttachNote(VRef,name,Info.fdCreator,Info.fdType);
  353.                                                 NoteAttached = true;
  354.                                 }
  355.                     }
  356.                     else
  357.                     {
  358.                                 State = AbDone;
  359.                                 return(False);
  360.                     }
  361.     } else {
  362.         PCopy(name,Name);
  363.                 if( AutoWantTheFile(name,&vRef,False)){
  364.                                 if( Rename( TmpName, VRef, name ) == noErr ){
  365.                                                 PCopy( Name, name );
  366.                                                 PCopy( TmpName, name );
  367.                                 } else { /* Rename failed, name stays TmpName */
  368.                                                 PCopy( name, TmpName );
  369.                                                 PCopy( Name, name );
  370.                                 }
  371.                 } else { /* Not auto downloading, so name has to remain the TMPname... */
  372.                                 PCopy( name, TmpName ); /* For the attach note */
  373.                                 PCopy( Name, name ); /* Set the real name back to the tmp name */
  374.                 }
  375.                 AbNextState();
  376.                 BSpot = 0;
  377.                 if( SeenFinfo ){
  378.                                 AddAttachNote(VRef,name,Info.fdCreator,Info.fdType);
  379.                                 NoteAttached = true;
  380.                 }
  381.     }
  382.     return(True);
  383. }
  384.  
  385. Boolean AbSetFinfo(uShort byte)
  386. {
  387.     Str63 name;
  388.     FInfo info;
  389.     short err;
  390.  
  391.                 if(!SeenFinfo){ /* Type 2 AppleSingle have additional FinderInfo (Sys 7) -- we don't care */
  392.                                 if( BSpot<sizeof(FInfo) ){
  393.                                                 InfoData[BSpot++] = byte;
  394.                                 } else {
  395.                                                 BSpot++;
  396.                                 }
  397.                                 if (BSpot<CurrMap.length) return(True);
  398.                                 SeenFinfo = true;
  399.                 }
  400.                 PCopy( name, Name );
  401.                 if( (!NoteAttached && SeenName) || !HasName ){
  402.                                 AddAttachNote(VRef,name,Info.fdCreator,Info.fdType);
  403.                 }
  404.                 info = Info;
  405.                 info.fdFlags &= ~fOnDesk;
  406.                 info.fdFlags &= ~fInvisible;
  407.                 info.fdFlags &= ~fInited;
  408.                 if (err=SetFInfo(name,VRef,&info))
  409.                 {
  410.                     FileSystemError(BINHEX_OPEN,name,err);
  411.                     (void) SaveAbomination(nil,0);
  412.                     return(False);
  413.                 }
  414.                 BSpot = 0;
  415.                 AbNextState();
  416.                 return(True);
  417. }
  418. /************************************************************************
  419.  *
  420.  ************************************************************************/
  421. short AbOpen(void)
  422. {
  423.     Str63 name;
  424.     short err;
  425.     short refN;
  426.     UHandle buffer;
  427.     
  428.     if (!Buffer)
  429.         if (buffer=NuHandle(GetRLong(RCV_BUFFER_SIZE)))
  430.             Buffer = buffer;
  431.         else
  432.             return(WarnUser(BINHEX_MEM,err=MemError()));
  433.     BSize = GetHandleSize(Buffer);
  434.     PCopy(name,Name);
  435.     if (err=(State==AbResFork?OpenRF(name,VRef,&refN):FSOpen(name,VRef,&refN)))
  436.         FileSystemError(BINHEX_OPEN,name,err);
  437.     else
  438.         RefN = refN;
  439.     BSpot = 0;
  440.     return(err);
  441. }
  442.  
  443. /************************************************************************
  444.  *
  445.  ************************************************************************/
  446. short AbClose(void)
  447. {
  448.     short wrErr=0;
  449.     short err;
  450.     
  451.     if (!RefN) return(noErr);
  452.     if (BSpot) wrErr = AbWriteBuffer();
  453.     err = FSClose(RefN);
  454.     if (!wrErr && err) FileSystemError(BINHEX_WRITE,Name,err);
  455.     RefN = 0;
  456.     BSpot = 0;
  457.     return(wrErr ? wrErr : err);
  458. }
  459.  
  460. /************************************************************************
  461.  *
  462.  ************************************************************************/
  463. short AbWriteBuffer(void)
  464. {
  465.     long writeBytes = BSpot;
  466.     int err;
  467.     
  468.     if (err=FSWrite(RefN,&writeBytes,LDRef(Buffer)))
  469.         FileSystemError(BINHEX_WRITE,Name,err);
  470.     UL(Buffer);
  471.     BSpot = 0;
  472.     return(err);
  473. }
  474.  
  475. Boolean AbNextState( void )
  476. {
  477.                 short i;
  478.                 long biggest = 0;
  479.  
  480.                 CurrMapNum = 0;
  481.                 for( i=0; i<Header.mapCount; i++){ /* Find the biggest offset */
  482.                                 if( Header.maps[i].offset > biggest ) biggest = Header.maps[i].offset + 1;
  483.                                 if( Header.maps[i].type == 3 ) HasName = true;
  484.                 }
  485.                 
  486.                 for( i=0; i<Header.mapCount; i++){ /* Find the header that is next */     
  487.                                 if ( (Header.maps[i].offset > Offset) && (Header.maps[i].offset < biggest) ) {
  488.                                                 CurrMapNum = i;
  489.                                                 biggest = CurrMap.offset + 1;
  490.                                                 switch (CurrMap.type){
  491.                                                                 case 1: /* Data Fork */
  492.                                                                                 State = AbDataFork;
  493.                                                                                 break;
  494.                                                                 case 2: /* Resource Fork */
  495.                                                                                 State = AbResFork;
  496.                                                                                 break;
  497.                                                                 case 3: /* Real file name */
  498.                                                                                 State = AbName;
  499.                                                                                 break;
  500.                                                                 case 9: /* File Finder information */
  501.                                                                                 State = AbFinfo;
  502.                                                                                 break;
  503.                                                                 default:
  504.                                                                                 AddAttachInfo( (int)UU_SKIP_MAP_INFO, (int)CurrMap.type );
  505.                                                                                 State = AbSkip;
  506.                                                                                 break;
  507.                                                 }
  508.                                 }
  509.                 }
  510.                 return( true );
  511. }
  512.  
  513.